// proto.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <google/protobuf/text_format.h>

#include <string>
#include <sstream>
#include "tinyxml/tinyxml.h"

template <class T>
bool from_string(T& t, 
                 const std::string& s, 
                 std::ios_base& (*f)(std::ios_base&))
{
  std::istringstream iss(s);
  return !(iss >> f >> t).fail();
}


int _tmain(int argc, _TCHAR* argv[])
{
	GOOGLE_PROTOBUF_VERIFY_VERSION;

	// a dotproto scene instance
	dotproto::Scene scene;

	// open xml document
	TiXmlDocument xml;
	if (!xml.LoadFile("testexport.xml"))
	{
		return false;
	}
	// get scene base node
	TiXmlElement* pSceneRootNode = xml.FirstChildElement("scene");
	if (!pSceneRootNode)
	{
		return false;
	}

	// loop through nodes
	TiXmlElement* pNodesNode = pSceneRootNode->FirstChildElement("nodes");
	for (TiXmlElement* pNode = pNodesNode->FirstChildElement();
		pNode != 0; pNode = pNode->NextSiblingElement())
	{

		// add a node the scene
		dotproto::Node* node = scene.add_node(); 

		// read position
		TiXmlElement* pPosition = pNode->FirstChildElement("position");
		float pos_x, pos_y, pos_z = 0.0f;
		from_string<float>(pos_x, pPosition->Attribute("x"), std::dec);
		from_string<float>(pos_y, pPosition->Attribute("y"), std::dec);
		from_string<float>(pos_z, pPosition->Attribute("z"), std::dec);

		// write position
		dotproto::Vec3f* pos = node->mutable_position();
		pos->set_x(pos_x);
		pos->set_y(pos_y);
		pos->set_z(pos_z);

		// read orientation
		TiXmlElement* pQuaternion = pNode->FirstChildElement("quaternion");
		float qw, qx, qy, qz = 0.0f;
		from_string<float>(qw, pQuaternion->Attribute("qw"), std::dec);
		from_string<float>(qx, pQuaternion->Attribute("qx"), std::dec);
		from_string<float>(qy, pQuaternion->Attribute("qy"), std::dec);
		from_string<float>(qz, pQuaternion->Attribute("qz"), std::dec);

		// write orientation
		dotproto::Quat4f* quat = node->mutable_quaternion();
		quat->set_w(qw);
		quat->set_x(qx);
		quat->set_y(qy);
		quat->set_z(qz);

		// read scale
		TiXmlElement* pScale = pNode->FirstChildElement("scale");
		float sx, sy, sz = 0.0f;
		from_string<float>(sx, pScale->Attribute("x"), std::dec);
		from_string<float>(sy, pScale->Attribute("y"), std::dec);
		from_string<float>(sz, pScale->Attribute("z"), std::dec);
		
		// write scale
		dotproto::Vec3f* scale = node->mutable_scale();
		scale->set_x(sx);
		scale->set_y(sy);
		scale->set_z(sz);

		// read and write entity
		TiXmlElement* pEntity = pNode->FirstChildElement("entity");
		dotproto::Entity* ent = node->mutable_entity();
		ent->set_name(pEntity->Attribute("name"));
		ent->set_meshfile(pEntity->Attribute("meshfile"));

		// See if there's any userData
		TiXmlElement* pUserdataNode = pNode->FirstChildElement("userData");
		if(pUserdataNode)
		{
			// Loop the properties
			for (TiXmlElement* pProperty = pUserdataNode->FirstChildElement();
				pProperty != 0; pProperty = pProperty->NextSiblingElement())
			{
				// read and write property
				dotproto::Property* prop1 = node->add_property();
				prop1->set_type(pProperty->Attribute("type"));
				prop1->set_name(pProperty->Attribute("name"));
				prop1->set_data(pProperty->Attribute("data"));
				
			}
		}
	}

	// Are we ready to write a protocul buffer?	
	if(scene.IsInitialized())
	{
		// write a protocol buffer in standard binary format.
		std::string path = "./" + std::string("test.pb");
		std::fstream output(path.c_str(), std::ios::out | std::ios::binary );
		scene.SerializeToOstream(&output);

		// write a protocol buffer in human readable text format.
		std::string theproto;
		google::protobuf::TextFormat::PrintToString(scene, &theproto);
		std::string thepath = "./" + std::string("test.txt");
		std::fstream textoutput(thepath.c_str(), std::ios::out | std::ios::binary );
		textoutput << theproto;
	}


	// Open protocol buffer for reading.
	std::string inpath = "./" + std::string("test.pb");
	std::fstream input(inpath.c_str(), std::ios::in | std::ios::binary );
	// Parse it
	scene.ParseFromIstream(&input);

	// Print the protocol buffer to the screen.
	
	// Loop through nodes in scene
	for (int i = 0; i < scene.node_size(); i++)
	{
		// grab a node
		const dotproto::Node& out_node = scene.node(i);
		// pretty print node values
		std::cout << "Node Position: " << out_node.position().x() << "," << out_node.position().y() << "," << out_node.position().z() << std::endl;
		std::cout << "Node Orientation: " << out_node.quaternion().w() << "," << out_node.position().x() << "," << out_node.position().y() << "," << out_node.position().z() << std::endl;
		std::cout << "Node Scale: " << out_node.scale().x() << "," << out_node.scale().y() << "," << out_node.scale().z() << std::endl;
		std::cout << "Node Entity name: " << out_node.entity().name() << std::endl;
		std::cout << "Node Entity meshfile: " << out_node.entity().meshfile() << std::endl;

		// Loop through userdata
		for (int i = 0; i < out_node.property_size(); i++)
		{
			// grab a property
			const dotproto::Property& out_property = out_node.property(i);
			// pretty print property values
			std::cout << "Node Userdata type: " << out_property.type() << std::endl;
			std::cout << "Node Userdata name: " << out_property.name() << std::endl;
			std::cout << "Node Userdata data: " << out_property.data() << std::endl;
		}
	}		

	return 0;
}

